using System;
using System.Collections.Generic;
using System.Text;

namespace SmartMathLibrary
{
    /// <summary>
    /// Provides the three most popular angle formats.
    /// </summary>
    public enum AngleKind
    {
        /// <summary>
        /// The normal degree format.
        /// </summary>
        Degree,
        /// <summary>
        /// The special gradian format.
        /// </summary>
        Gradian,
        /// <summary>
        /// The radian format.
        /// </summary>
        Radian
    }

    /// <summary>
    /// This class represents an angle and its normal operations.
    /// </summary>
    [Serializable]
    public class Angle : IAngle
    {
        /// <summary>
        /// The angle in radians.
        /// </summary>
        private double radians;

        /// <summary>
        /// Initializes a new instance of the <see cref="Angle"/> class.
        /// </summary>
        /// <param name="value">The value of the angle.</param>
        /// <param name="kind">The kind of angle.</param>
        public Angle(double value, AngleKind kind)
        {
            switch (kind)
            {
                case AngleKind.Degree:
                    this.radians = ExtendedMath.ToRadians(value);
                    break;

                case AngleKind.Radian:
                    this.radians = value;
                    break;

                case AngleKind.Gradian:
                    this.radians = ExtendedMath.ToRadians(value * 9 / 10);
                    break;
            }

            ExtendedMath.ToRadians(value);
        }

        /// <summary>
        /// Gets or sets the radians of the current angle object.
        /// </summary>
        /// <value>The radians of the current angle object.</value>
        public double Radians
        {
            get { return radians; }
            set { radians = value; }
        }

        /// <summary>
        /// Calculates the sin of the current angle.
        /// </summary>
        /// <returns>The sin value of the current angle.</returns>
        public double Sin()
        {
            return Math.Sin(this.radians);
        }

        /// <summary>
        /// Calculates the cos of the current angle.
        /// </summary>
        /// <returns>The cos value of the current angle.</returns>
        public double Cos()
        {
            return Math.Cos(this.radians);
        }

        /// <summary>
        /// Calculates the tan of the current angle.
        /// </summary>
        /// <returns>The tan value of the current angle.</returns>
        public double Tan()
        {
            return Math.Tan(this.radians);
        }

        /// <summary>
        /// Calculates the arcos of the current angle.
        /// </summary>
        /// <returns>The acos value of the current angle.</returns>
        public double Acos()
        {
            return Math.Acos(this.radians);
        }

        /// <summary>
        /// Calculates the asin of the current angle.
        /// </summary>
        /// <returns>The asin value of the current angle.</returns>
        public double Asin()
        {
            return Math.Asin(this.radians);
        }

        /// <summary>
        /// Calculates the atan of the current angle.
        /// </summary>
        /// <returns>The atan value of the current angle.</returns>
        public double Atan()
        {
            return Math.Atan(this.radians);
        }

        /// <summary>
        /// Calculates the cosh of the current angle.
        /// </summary>
        /// <returns>The cosh value of the current angle.</returns>
        public double Cosh()
        {
            return Math.Cosh(this.radians);
        }

        /// <summary>
        /// Calculates the sinh of the current angle.
        /// </summary>
        /// <returns>The sinh value of the current angle.</returns>
        public double Sinh()
        {
            return Math.Sinh(this.radians);
        }

        /// <summary>
        /// Calculates the tanh of the current angle.
        /// </summary>
        /// <returns>The tanh value of the current angle.</returns>
        public double Tanh()
        {
            return Math.Tanh(this.radians);
        }

        /// <summary>
        /// Compares the current instance to another angle object.
        /// </summary>
        /// <param name="compare">The instance to compare.</param>
        /// <returns>True if the radians of both instances are even otherwise, false.</returns>
        public bool CompareTo(Angle compare)
        {
            if (compare == (Angle) null)
            {
                throw new ArgumentNullException("compare");
            }

            return (compare.radians == this.radians);
        }

        /// <summary>
        /// Copies the current instance of the angle object.
        /// </summary>
        /// <returns>A copy of the current instance.</returns>
        public Angle Copy()
        {
            return new Angle(this.radians, AngleKind.Radian);
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
        /// </returns>
        /// <exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is null.</exception>
        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            return this.radians.ToString();
        }
    }
}